package com.sduept.nwld.dataserver.manager.cim;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;

import com.sduept.core.dao.SuperDAO;
import com.sduept.generator.ObjectId;
import com.sduept.cim.ledger.total.model.PrimaryDeviceCount;
import com.sduept.utils.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 一次设备统计表生成Manager
 */
@Service
public class PrimaryDeviceCountPersistenceManager {


	private static final String stationTemplate  = "SELECT #{unit} as unitName,d.standVoltagelevel as voltageLevel,COUNT(*) as statisticCount  FROM t_cim_substation d LEFT JOIN t_primary_equipment_ledger l ON d.id = l.cimId  GROUP BY #{unit},d.standVoltagelevel";
	private static final String stationDeviceTemplate = "SELECT #{unit}  as unitName,d.standVoltagelevel  as voltageLevel,COUNT(*) as statisticCount FROM #{table} d LEFT JOIN t_primary_equipment_ledger l ON d.sub_id = l.cimId  GROUP BY #{unit},d.standVoltagelevel ";
	private static final String lineTemplate = "SELECT #{unit}  as unitName,d.standVoltagelevel  as voltageLevel,COUNT(*) as statisticCount FROM t_cim_aclinesegment d LEFT JOIN t_primary_equipment_ledger l ON d.id = l.cimId  GROUP BY #{unit},d.standVoltagelevel ";
	private static final String dispatchColumn = "l.dispatchUnit";
	private static final String maintenanceColumn = "l.primaryEquipmentScope";

	@Autowired
	private SuperDAO dao;


	/**
	 * 调管范围设备统计
	 * @param overideManual 覆盖状态
	 */
	public void persistenceDispatchStatisticCount(boolean overideManual) {
		Byte unitType = 0;
		persistenceSubstationCount(unitType,overideManual)
				.persistenceBusbarSectionCount(unitType,overideManual)
				.persistenceLineCount(unitType,overideManual)
				.persistencePowerTransformerCount(unitType,overideManual)
				.persistenceBreakerCount(unitType,overideManual)
				.persistenceGeneratorCount(unitType,overideManual);
	}

	/**
	 * 检修范围设备统计
	 */
	public void persistenceMaintenanceStatisticCount(boolean overideManual) {
		Byte unitType = 1;
		persistenceSubstationCount(unitType,overideManual)
				.persistenceBusbarSectionCount(unitType,overideManual)
				.persistenceLineCount(unitType,overideManual)
				.persistencePowerTransformerCount(unitType,overideManual)
				.persistenceBreakerCount(unitType,overideManual)
				.persistenceGeneratorCount(unitType,overideManual);
	}

	/**
	 * 变电站统计插入
	 * @return
	 */
	private PrimaryDeviceCountPersistenceManager  persistenceSubstationCount(Byte unitType,boolean overideManual) {
		List<PrimaryDeviceCount> list = new ArrayList<PrimaryDeviceCount>();
		if(unitType ==0) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.substation.getDispatchQuerySql(), new Object[]{});
		}else if(unitType == 1) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.substation.getMaintenanceQuerySql(), new Object[]{});
		}

		if(list.isEmpty()) {
			return this;
		}
		List<PrimaryDeviceCount> insertDatas = transformer(list,StatisticType.substation.getType(),unitType);
		if(overideManual) {
			persistencePrimaryDeviceCountOveride(unitType,insertDatas,StatisticType.substation.getType());
		}else {
			persistencePrimaryDeviceCountUnOveride(unitType,insertDatas,StatisticType.substation.getType());
		}
		return this;
	}


	/**
	 * 不覆盖人工更改
	 * @param unitType
	 * @param insertDatas
	 * @param deviceType
	 */
	private void persistencePrimaryDeviceCountUnOveride(Byte unitType, List<PrimaryDeviceCount> insertDatas, Byte deviceType) {
		if(CollectionUtils.isEmpty(insertDatas)) {
			return;
		}
		Date statisticTime = insertDatas.get(0).getStatisticTime();
		Date start = getStartDate();
		Date end = getEndDate();
		//清楚掉规定时间内自动统计的数据
		dao.delete(PrimaryDeviceCount.class, "unitType=? AND statisticType =? AND operateStatus=0 AND statisticTime BETWEEN ? AND ?",unitType,deviceType, start,end);
		//获取人工填报的数据，用于过滤传入的参数
		List<PrimaryDeviceCount> dblist = dao.findByCondition(PrimaryDeviceCount.class,"operateStatus=1 AND statisticTime BETWEEN ? AND ?", start,end);
		outer:
		for(PrimaryDeviceCount d:insertDatas) {
			for(PrimaryDeviceCount db:dblist) {
				if(db.getUnitName().equals(d.getUnitName())
						&& db.getVoltageLevel().equals(d.getVoltageLevel())
						&& db.getStatisticType().equals(d.getStatisticType())) {
					db.setStatisticTime(statisticTime);
					dao.createOrUpdate(db,PrimaryDeviceCount.class);
					continue outer;
				}
			}
			dao.createOrUpdate(d,PrimaryDeviceCount.class);
		}
	}
	/**
	 * 覆盖人工更新
	 * @param unitType
	 * @param insertDatas
	 * @param deviceType
	 */
	private void persistencePrimaryDeviceCountOveride(Byte unitType, List<PrimaryDeviceCount> insertDatas, Byte deviceType) {
		Date start = getStartDate();
		Date end = getEndDate();
		dao.delete(PrimaryDeviceCount.class, "unitType=? AND statisticType =? AND statisticTime BETWEEN ? AND ?", unitType,deviceType,start,end);
		for(PrimaryDeviceCount d:insertDatas) {
			dao.createOrUpdate(d,PrimaryDeviceCount.class);
		}

	}

	/**
	 * 母线统计插入
	 * @param unitType
	 * @return
	 */
	private PrimaryDeviceCountPersistenceManager  persistenceBusbarSectionCount(Byte unitType,boolean overideManual) {
		//变电站查询
		List<PrimaryDeviceCount> list = new ArrayList<PrimaryDeviceCount>();
		if(unitType ==0) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.busbarsection.getDispatchQuerySql(), new Object[]{});
		}else if(unitType == 1) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.busbarsection.getMaintenanceQuerySql(), new Object[]{});
		}
		if(list.isEmpty()) {
			return this;
		}
		List<PrimaryDeviceCount> insertDatas = transformer(list,StatisticType.busbarsection.getType(),unitType);
		if(overideManual) {
			persistencePrimaryDeviceCountOveride(unitType,insertDatas,StatisticType.busbarsection.getType());
		}else {
			persistencePrimaryDeviceCountUnOveride(unitType,insertDatas,StatisticType.busbarsection.getType());
		}
		return this;
	}

	/**
	 * 线路统计插入
	 * @param year
	 * @return
	 */
	private PrimaryDeviceCountPersistenceManager persistenceLineCount(Byte unitType,boolean overideManual) {
		List<PrimaryDeviceCount> list = new ArrayList<PrimaryDeviceCount>();
		if(unitType ==0) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.line.getDispatchQuerySql(), new Object[]{});
		}else if(unitType == 1) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.line.getMaintenanceQuerySql(), new Object[]{});
		}
		if (list.isEmpty()) {
			return this;
		}
		List<PrimaryDeviceCount> insertDatas = transformer(list, StatisticType.line.getType(), unitType);
		if(overideManual) {
			persistencePrimaryDeviceCountOveride(unitType,insertDatas,StatisticType.line.getType());
		}else {
			persistencePrimaryDeviceCountUnOveride(unitType,insertDatas,StatisticType.line.getType());
		}
		return this;
	}

	/**
	 * 变压器统计插入
	 * @param unitType2
	 * @param year
	 * @return
	 */
	private PrimaryDeviceCountPersistenceManager persistencePowerTransformerCount(Byte unitType,boolean overideManual) {
		List<PrimaryDeviceCount> list = new ArrayList<PrimaryDeviceCount>();
		if(unitType ==0) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.powertransformer.getDispatchQuerySql(), new Object[]{});
		}else if(unitType == 1) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.powertransformer.getMaintenanceQuerySql(), new Object[]{});
		}
		if (list.isEmpty()) {
			return this;
		}
		List<PrimaryDeviceCount> insertDatas = transformer(list, StatisticType.powertransformer.getType(), unitType);
		if(overideManual) {
			persistencePrimaryDeviceCountOveride(unitType,insertDatas,StatisticType.powertransformer.getType());
		}else {
			persistencePrimaryDeviceCountUnOveride(unitType,insertDatas,StatisticType.powertransformer.getType());
		}
		return this;
	}

	/**
	 * 断路器统计插入
	 * @param unitType
	 * @param year
	 * @return
	 */
	private PrimaryDeviceCountPersistenceManager persistenceBreakerCount(Byte unitType,boolean overideManual) {
		List<PrimaryDeviceCount> list = new ArrayList<PrimaryDeviceCount>();
		if(unitType ==0) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.breaker.getDispatchQuerySql(), new Object[]{});
		}else if(unitType == 1) {
			list = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.breaker.getMaintenanceQuerySql(), new Object[]{});
		}
		if (list.isEmpty()) {
			return this;
		}
		List<PrimaryDeviceCount> insertDatas = transformer(list, StatisticType.breaker.getType(), unitType);
		if(overideManual) {
			persistencePrimaryDeviceCountOveride(unitType,insertDatas,StatisticType.breaker.getType());
		}else {
			persistencePrimaryDeviceCountUnOveride(unitType,insertDatas,StatisticType.breaker.getType());
		}
		return this;
	}

	/**
	 * 发电机统计插入
	 * @param unitType
	 * @param year
	 * @return
	 */
	private PrimaryDeviceCountPersistenceManager persistenceGeneratorCount(Byte unitType,boolean overideManual) {
		List<PrimaryDeviceCount> list = new ArrayList<PrimaryDeviceCount>();
		if(unitType ==0) {
			List<PrimaryDeviceCount> list1 = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.hydrogeneratingunit.getDispatchQuerySql(), new Object[]{});
			List<PrimaryDeviceCount> list2 = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.generatingunit.getDispatchQuerySql(), new Object[]{});
			List<PrimaryDeviceCount> list3 = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.thermalgeneratingunit.getDispatchQuerySql(), new Object[]{});
			list.addAll(list1);
			list.addAll(list2);
			list.addAll(list3);
		}else if(unitType == 1) {
			List<PrimaryDeviceCount> list1 = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.hydrogeneratingunit.getMaintenanceQuerySql(), new Object[]{});
			List<PrimaryDeviceCount> list2 = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.generatingunit.getMaintenanceQuerySql(), new Object[]{});
			List<PrimaryDeviceCount> list3 = dao.nativeQuery( PrimaryDeviceCount.class,StatisticType.thermalgeneratingunit.getMaintenanceQuerySql(), new Object[]{});
			list.addAll(list1);
			list.addAll(list2);
			list.addAll(list3);
		}
		if (list.isEmpty()) {
			return this;
		}
		List<PrimaryDeviceCount> insertDatas = transformer(list, StatisticType.generatingunit.getType(), unitType);
		if(overideManual) {
			persistencePrimaryDeviceCountOveride(unitType,insertDatas,StatisticType.generatingunit.getType());
		}else {
			persistencePrimaryDeviceCountUnOveride(unitType,insertDatas,StatisticType.generatingunit.getType());
		}
		return this;
	}


	/**
	 * 转换
	 * @param list
	 * @param busbarsectionType
	 * @param unitType
	 * @return
	 */
	private List<PrimaryDeviceCount>  transformer(List<PrimaryDeviceCount> list, Byte busbarsectionType,Byte unitType) {
		List<PrimaryDeviceCount>  result  = new ArrayList<PrimaryDeviceCount>();
		list.stream().map(p->{
			if(StringUtils.isBlank(p.getUnitName())) {
				p.setUnitName("未设置管理单位");
			}
			p.setId(ObjectId.get().toString());
			p.setUnitType(unitType);
			p.setStatisticType(busbarsectionType);
			p.setStatisticTime(new Date());
			return p;
		}).collect(Collectors.groupingBy(p->p.getUnitName()+"/"+p.getVoltageLevel()))
				.forEach((k,v)->{
					Optional<PrimaryDeviceCount> reduce = v.stream().reduce((v1,v2)->{
						v1.setStatisticCount(v1.getStatisticCount()+v2.getStatisticCount());
						return v1;
					});
					result.add(reduce.get());
				});
		return result;

	}
	public enum StatisticType{
		substation {
			@Override
			String getDispatchQuerySql() {
				String sql = stationTemplate.replace("#{unit}", dispatchColumn);
				return sql;
			}

			@Override
			String getMaintenanceQuerySql() {
				String sql  = stationTemplate.replace("#{unit}", maintenanceColumn);
				return sql;
			}
			@Override
			public Byte getType() {
				Byte  type = 0;
				return type;
			}

		},busbarsection {
			String sql = stationDeviceTemplate.replace("#{table}", "t_cim_busbarsection");
			@Override
			String getDispatchQuerySql() {
				sql = sql.replace("#{unit}", dispatchColumn);
				return sql;
			}

			@Override
			String getMaintenanceQuerySql() {
				sql = sql.replace("#{unit}", maintenanceColumn);
				return sql;
			}
			@Override
			public Byte getType() {
				Byte  type = 1;
				return type;
			}

		},line {
			@Override
			String getDispatchQuerySql() {
				String sql = lineTemplate.replace("#{unit}", dispatchColumn);
				return sql;
			}

			@Override
			String getMaintenanceQuerySql() {
				String sql = lineTemplate.replace("#{unit}", maintenanceColumn);
				return sql;
			}
			@Override
			public	Byte getType() {
				Byte  type = 2;
				return type;
			}

		},powertransformer {
			String sql = stationDeviceTemplate.replace("#{table}", "t_cim_powertransformer");
			@Override
			String getDispatchQuerySql() {
				sql = sql.replace("#{unit}", dispatchColumn);
				return sql;
			}

			@Override
			String getMaintenanceQuerySql() {
				sql = sql.replace("#{unit}", maintenanceColumn);
				return sql;
			}
			@Override
			public Byte getType() {
				Byte  type = 3;
				return type;
			}

		},breaker {
			String sql = stationDeviceTemplate.replace("#{table}", "t_cim_breaker");
			@Override
			String getDispatchQuerySql() {
				sql = sql.replace("#{unit}", dispatchColumn);
				return sql;
			}

			@Override
			String getMaintenanceQuerySql() {
				sql = sql.replace("#{unit}", maintenanceColumn);
				return sql;
			}
			@Override
			public	Byte getType() {
				Byte  type = 4;
				return type;
			}
		},hydrogeneratingunit {//水轮发电机
			String sql = stationDeviceTemplate.replace("#{table}", "t_cim_hydrogeneratingunit");
			@Override
			String getDispatchQuerySql() {
				sql = sql.replace("#{unit}", dispatchColumn);
				return sql;
			}

			@Override
			String getMaintenanceQuerySql() {
				sql = sql.replace("#{unit}", maintenanceColumn);
				return sql;
			}

			@Override
			public Byte getType() {
				Byte  type = 5;
				return type;
			}


		},generatingunit {//发电机
			String sql = stationDeviceTemplate.replace("#{table}", "t_cim_generatingunit");
			@Override
			String getDispatchQuerySql() {
				sql = sql.replace("#{unit}", dispatchColumn);
				return sql;
			}

			@Override
			String getMaintenanceQuerySql() {
				sql = sql.replace("#{unit}", maintenanceColumn);
				return sql;
			}

			@Override
			public Byte getType() {
				Byte  type = 5;
				return type;
			}


		},thermalgeneratingunit {//火力发电机
			String sql = stationDeviceTemplate.replace("#{table}", "t_cim_thermalgeneratingunit");
			@Override
			String getDispatchQuerySql() {
				sql = sql.replace("#{unit}", dispatchColumn);
				return sql;
			}

			@Override
			String getMaintenanceQuerySql() {
				sql = sql.replace("#{unit}", maintenanceColumn);
				return sql;
			}

			@Override
			public Byte getType() {
				Byte  type = 5;
				return type;
			}


		};
		abstract  String getDispatchQuerySql();
		abstract String getMaintenanceQuerySql();
		public abstract   Byte getType();
	}

	/**
	 *        根据年、人工更新状态和单位类型进行删除
	 * @param year
	 * @param status
	 * @param unitType
	 */
	public void deleteByYearOperateStatusUnitType(int year,boolean status,Byte unitType) {
		Date start = getStartTime(year);
		Date end = getEndTime(year);
		if(status == true) {
			dao.delete(PrimaryDeviceCount.class, "unitType =? and statisticTime between ? and ?", new Object[] {unitType,start,end});
		}else {
			dao.delete(PrimaryDeviceCount.class, "operateStatus = 0  and unitType =? and  statisticTime between ? and ? ", new Object[] {unitType,start,end});
		}
	}

	/**
	 * 根据年份获得查询的起始时间
	 * @param year
	 * @return
	 */
	private Date getStartTime(int year) {
		return DateUtil.getDateByString(year+"-01-01", DateUtil.pattern_ymd);
	}
	/**
	 * 根据年份获得查询时间的结束时间
	 * @param year
	 * @return
	 */
	private Date getEndTime(int year) {
		return DateUtil.getDateByString((year+1)+"-12-31", DateUtil.pattern_ymd);
	}
	/**
	 * 获得查询语句的开始时间
	 * @return
	 */
	private Date getStartDate() {
		Calendar instance = Calendar.getInstance();
		int year = instance.get(Calendar.YEAR);
		Date start = DateUtil.getDateByString(year+"-01-01",DateUtil.pattern_ymd);
		return start;
	}
	/**
	 * 获得查询语句的结束时间
	 * @return
	 */
	private Date getEndDate() {
		Calendar instance = Calendar.getInstance();
		int year = instance.get(Calendar.YEAR);
		Date start = DateUtil.getDateByString((year+1)+"-01-01",DateUtil.pattern_ymd);
		return start;
	}

	public void update(PrimaryDeviceCount count) {
		dao.update(count, PrimaryDeviceCount.class);

	}

	public void save(PrimaryDeviceCount c) {
		dao.create(c, PrimaryDeviceCount.class);

	}
}
